package dao

import (
	"context"
	"encoding/json"
	"errors"
	"fmt"
	"gbox-one-machine/conf"
	"github.com/go-resty/resty/v2"
	"net/http"
)

// errors
var (
	ErrDataEmpty = errors.New("Data is empty")
)

// Dao database
type Dao struct {
	conn          *Conn
	conf          *conf.Dao
	resCenterHost string
	chQuit        chan struct{}
}

// New Dao
func New(c *conf.Dao) (*Dao, error) {

	conn, err := GetConn(c)
	if err != nil {
		return nil, err
	}

	return &Dao{
		conn:          conn,
		conf:          c,
		resCenterHost: fmt.Sprintf("http://%s:%d", c.ResCenter.Host, c.ResCenter.Port),
		chQuit:        make(chan struct{}),
	}, nil
}

func (d *Dao) http() *resty.Client {
	return d.conn.httpConn
}

// Close close db connect
func (d *Dao) Close() error {
	close(d.chQuit)
	return nil
}

type longPollResp struct {
	ReturnCode   int    `json:"returnCode"`
	ErrorMessage string `json:"errorMessage"`
}

const longPollTimeoutCode = 2

// SubLongPoll subscribe long polling service
func (d *Dao) SubLongPoll(ctx context.Context, url string, cb func(data []byte) error) error {
	resResp := new(longPollResp)
	for {
		select { // quit first
		case <-d.chQuit:
			return nil
		default:
		}

		resp, err := d.http().R().SetContext(ctx).Get(url)
		if err != nil {
			return fmt.Errorf("HTTP request err: %s", err)
		}

		if resp.StatusCode() != http.StatusOK {
			return fmt.Errorf("HTTP status %s", resp.Status())
		}

		if err := json.Unmarshal(resp.Body(), resResp); err != nil {
			return fmt.Errorf("Resp decode err: %s body: %s", err, resp.Body())
		}

		if resResp.ReturnCode != 0 {
			if resResp.ReturnCode == longPollTimeoutCode { // normal longpoll timeout
				continue
			}

			return fmt.Errorf("Errcode: %d, Msg: %s", resResp.ReturnCode, resResp.ErrorMessage)
		}

		if err := cb(resp.Body()); err != nil {
			return err
		}
	}
}


